#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <stdbool.h>
#include <pthread.h>
#include <semaphore.h>

#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/fb.h>
#include <linux/un.h>

#include <arpa/inet.h>
#include <netinet/in.h>

#include "sqlite3.h"
#include "fifo.h"


int fifo_in, fifo_out;
int fifo_v4l2;
int fifo_alsa;
int fifo_car;
char *err;
char SQL[200];

// 每当得到一行（即一个记录）就会调用一次以下函数
// len: 列数目
// col_val:  每一列的值
// col_name: 每一列的标题
//
// 返回值: 0: 继续对剩下的记录调用该函数
//       非0: 终止调用该函数

bool first = true;

int callback(void *arg, int len, char **col_val, char **col_name)
{
	// 1，检测库中是否有相应的卡号
	if(arg != NULL)
	{
		printf("time:%ld\n",time(NULL));
		(*(int *)arg) = time(NULL) - atol(col_val[2]);
		return 0;
	}

	// 2，显示当前数据库的信息
	// 针对第一行记录调用本函数的时候，就显示标题
	if(first)
	{
		printf("\n");
		for(int i=0; i<len; i++)
		{
			printf("%s\t\t", col_name[i]);
		}
		first = false;
		printf("\n=====================");
		printf("=====================\n");
	}

	for(int i=0; i<len; i++)
	{
		printf("%s\t", col_val[i]);
	}
	printf("\n");

	return 0;
}

int Sqlite3_exec(sqlite3 *db, char *SQL, int (*callback)(void *,int,char**,char**), void *arg, char **errmsg)
{
	int ret = sqlite3_exec(db, SQL, callback, arg, errmsg);
	if(ret != SQLITE_OK)
	{
		printf("执行[%s]失败: %s\n", SQL, *errmsg);
		exit(0);
	}
}

// 随机生成一个车牌号
char *licsen(void)
{
	return "黑A56LJ8";
}
char *get_cost(int hour,int minute)
{
	int spend= 0;
	
	if(hour >= 14 && hour<24)
	{
		spend = 80;
				
	}
	else if(hour/24 >=1)
	{
		// 25 - 24/24*24->1
		//48 -48/24*24 ->0
		//44 -44/24*24 ->20
		spend = 80*(hour/24);
		hour = hour - (hour/24)*24;
		if(hour >=14)
		{
			spend = 80 +spend;
		}
		else
		{
		spend= 6*hour + (minute/20)*2 + spend;
		}
	}
	else
	{
		spend= 6*hour + (int)(minute/20)*2 ;
	}
	
	char *cost=calloc(1,60);
	if(spend >10 && spend <100)
	{
		if(spend%10 == 0)
		{
			snprintf(cost,60,"收费%d十元",(spend/10%10));
		}
		else{
		snprintf(cost,60,"收费%d十%d元",(spend/10%10),(spend/1%10));
		}
	}
	if(spend >=100)
	{
		if((spend%10 ==0) && (spend/10%10 ==0))
		{
			snprintf(cost,60,"收费%d百元",(spend/10%10));
		}
		else if(spend/10%10 ==0)
		{
			snprintf(cost,60,"收费%d百零%d元",(spend/100%10),(spend/1%10));
		}
		else if(spend%10 == 0)
		{
			snprintf(cost,60,"收费%d百%d十元",(spend/100%10),(spend/10%10));
		}
		else
		{
		snprintf(cost,60,"收费%d百%d十%d元"
			,(spend/100%10),(spend/10%10),(spend%10));
		}
	}
	if(spend == 0)
	{
		snprintf(cost,60,"收费0元");
	}
	
	return cost;
}
char *get_leftmsg(int seconds)
{
	//20min ->$2 
	//1H=3*20min ->$6
	
	printf("seconds:%d\n",seconds);
	int hour= 0;
	int minute= 0;
	int spend= 0;
	char *leftInfo= calloc(1,200);
	bzero(leftInfo,200);
		
	
	minute= seconds /60;
	hour= minute/60;
	minute= (minute - hour*60) %60;
	
	spend= 6*hour + (int)(minute/20)*2;
	char *cost= get_cost(hour,minute);
	
	if(minute>= 10)
	{
		
		if(hour ==0)
		{
			snprintf(leftInfo,200,"停车时长%d十%d分，%s"
			,(minute/10%10),(minute/1%10),cost);
			
		}
		else if(hour >10)
		{
			snprintf(leftInfo,200,"停车时长%d十%d小时%d十%d分，%s"
			,(hour/10%10),(hour/1%10),(minute/10%10),(minute/1%10),cost);
		}
		else
		{
		snprintf(leftInfo,200,"停车时长%d小时%d十%d分，%s"
		,hour,(minute/10%10),(minute/1%10),cost);
		}
	}
	
	if(hour <10 && minute <10)
	{
		if(hour ==0)
		{
			snprintf(leftInfo,200,"停车时长%d分，%s"
			,minute,cost);
		}
		else
		{
			snprintf(leftInfo,200,"停车时长%d小时%d分，%s"
			,hour,minute,cost);
		}
	}
	return leftInfo;
}


void beep(int times, float sec)
{
	int buz = open("/dev/beep", O_RDWR);
	if(buz <= 0)
	{
		perror("打开蜂鸣器失败");
		return;
	}

	for(int i=0; i<times; i++)
	{
		// 响
		ioctl(buz, 0, 1);
		usleep(sec*1000*1000);

		// 静
		ioctl(buz, 1, 1);
		usleep(sec*1000*1000);
	}

	close(buz);
}

// 处理入库
void *routine(void *arg)
{
	sqlite3* db = (sqlite3 *)arg;
	char sedalsa_i[200];
	while(1)
	{
		uint32_t id;
		read(fifo_in, &id, sizeof(id));
		int shoot = 0;
		char carnumber[20];
		// 判断卡片的合法性
		bzero(SQL, 200);
		snprintf(SQL, 200, "SELECT * FROM carinfo WHERE 卡号='%u';", id);
		int n = 0;
		Sqlite3_exec(db, SQL, callback, (void *)&n, &err);
		if(n != 0)
		{
			printf("【此卡已进场】\n");
			beep(5, 0.05);
			continue;
		}
		else
		{
			shoot= 1;
			write(fifo_v4l2, &shoot, sizeof(shoot));
			
			
			
			beep(1, 0.3);
			bzero(carnumber,20);
			read(fifo_car,carnumber,20);
			
			printf("%s\n",carnumber);
			
			bzero(sedalsa_i,sizeof(sedalsa_i));
			snprintf(sedalsa_i,200,"欢迎%s入场" 
				, carnumber/*,licsen()*/);
			write(fifo_alsa,sedalsa_i,strlen(sedalsa_i));
			
			
			printf("欢迎%s入场\n"
			,carnumber/*,licsen()*/);
			//beep(1, 0.3);
		}

		bzero(SQL, 200);
		snprintf(SQL, 200, "INSERT INTO carinfo VALUES('%u', '%s', '%ld');"
			, id, carnumber/*,licsen()*/, time(NULL));
		Sqlite3_exec(db, SQL, NULL, NULL, &err);

		// 查询当前数据库中的数据
		bzero(SQL, 200);
		snprintf(SQL, 200, "SELECT * FROM carinfo;");
		Sqlite3_exec(db, SQL, callback, NULL, &err);
		printf("=====================");
		printf("=====================\n");
		first = true;
	}
}

int main(int argc, char **argv)
{
	// 1，创建、打开一个数据库文件
	sqlite3 *db = NULL;
	int ret = sqlite3_open_v2("parking.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
	if(ret != SQLITE_OK)
	{
		printf("创建数据库文件失败: %s\n", sqlite3_errmsg(db));
		exit(0);
	}


	// 2，创建表
	bzero(SQL, 200);
	snprintf(SQL, 200, "%s", "CREATE TABLE IF NOT EXISTS carinfo(卡号 TEXT, 车牌 TEXT, 入库时间 TEXT);");
	Sqlite3_exec(db, SQL, NULL, NULL, &err);


	// 打开管道
	fifo_in  = open(RFID_SQLite_in,  O_RDWR);
	fifo_out = open(RFID_SQLite_out, O_RDWR);
	fifo_v4l2= open(SQLite_V4L2,O_RDWR);
	fifo_alsa= open(SQLite_ALSA,O_RDWR);
	fifo_car= open(SQLite_CAR,O_RDWR);
	// 3，创建线程，等待入库卡号
	pthread_t tid;
	pthread_create(&tid, NULL, routine, (void *)db);


	// 3，主线程，等待出库的卡号
	char sedalsa_o[200];
	while(1)
	{
		uint32_t id;
		read(fifo_out, &id, sizeof(id));

		// 判断卡片是否合法
		bzero(SQL, 200);
		snprintf(SQL, 200, "SELECT * FROM carinfo WHERE 卡号='%u';", id);
		int seconds = 0;
	
		Sqlite3_exec(db, SQL, callback, (void *)&seconds, &err);
		if(seconds == 0)
		{
			printf("【此卡未进场】\n");
			beep(5, 0.05);
			continue;
		}
		else
		{
			
			bzero(sedalsa_o,sizeof(sedalsa_o));
			char *leftInfo= get_leftmsg(seconds);
			write(fifo_alsa,leftInfo,strlen(leftInfo));
			
			printf("%s\n",leftInfo);
			beep(1, 0.3);
		}

		// 出库
		bzero(SQL, 200);
		snprintf(SQL, 200, "DELETE FROM carinfo WHERE 卡号='%u';", id);
		Sqlite3_exec(db, SQL, NULL, NULL, &err);

		// 查询当前数据库中的数据
		bzero(SQL, 200);
		snprintf(SQL, 200, "SELECT * FROM carinfo;");
		Sqlite3_exec(db, SQL, callback, NULL, &err);
		printf("=====================");
		printf("=====================\n");
		first = true;
	}


	return 0;
}
